package com.xuhuan.server.business.splitfile.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.xuhuan.server.business.splitfile.entity.FileSplitReceive;
import com.xuhuan.server.business.splitfile.properties.FileSplitProperties;
import com.xuhuan.server.business.splitfile.service.IFileSplitFacadeService;
import com.xuhuan.server.business.splitfile.service.IFileSplitReceiveService;
import com.xuhuan.server.business.splitfile.vo.ZoneMd5ListVO;
import com.xuhuan.server.business.splitfile.vo.ZoneCheckRequestVO;
import com.xuhuan.server.business.splitfile.vo.ZoneUploadVO;
import com.xuhuan.server.util.CompareUtil;
import com.xuhuan.server.util.FileCombineUtill;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author huan.xu
 * @Date 2023/6/19 14:12
 * @Description
 */
@Slf4j
@Service
public class FileSplitFacadeServiceImpl implements IFileSplitFacadeService {

    @Autowired
    private FileSplitProperties fileSplitProperties;
    @Autowired
    private IFileSplitReceiveService fileSplitReceiveService;

    /**
     * 获取参数配置
     *
     * @return
     */
    @Override
    public FileSplitProperties getFileSplitProperties() {
        return fileSplitProperties;
    }

    /**
     * 接收单个分片文件
     *
     * @param zoneUploadVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receiveSignZoneFile(ZoneUploadVO zoneUploadVO) {
        String saveFilePath = fileSplitProperties.getTempBasePath()
                + File.separator + zoneUploadVO.getZoneProfixName()
                + File.separator + zoneUploadVO.getFileFullName();
        log.info("要创建的文件路径为：{}", saveFilePath);
        File saveFile = new File(saveFilePath);

        try {
            FileUtils.writeByteArrayToFile(saveFile, zoneUploadVO.getFileContent());

            //保存分片信息到数据库
            FileSplitReceive fileSplitReceive = new FileSplitReceive();
            fileSplitReceive.setZonePath(saveFile.getPath());
            fileSplitReceive.setZoneName(saveFile.getName());
            fileSplitReceive.setZoneMd5(zoneUploadVO.getZoneMd5());
            fileSplitReceive.setFileMd5(zoneUploadVO.getFileMd5());
            fileSplitReceiveService.saveOrUpdate(fileSplitReceive);
        } catch (IOException e) {
            log.info("接收单个分片文件失败:{}", ExceptionUtils.getFullStackTrace(e));
            throw new RuntimeException(e);
        }
    }

    /**
     * 检查分片信息，返回协会现有的分片数据，下次就只需要再上传缺失的分片数据
     *
     * @param requestVO
     * @return
     */
    @Override
    public ZoneMd5ListVO checkZoneFile(ZoneCheckRequestVO requestVO) {
        ZoneMd5ListVO zoneMd5ListVO = new ZoneMd5ListVO();
        List<String> zoneMd5List =new ArrayList<>();
        List<FileSplitReceive> fileSplitReceiveList = fileSplitReceiveService.findByFileMd5(requestVO.getFileMd5());
        if(CollectionUtils.isNotEmpty(fileSplitReceiveList)){
            zoneMd5List = fileSplitReceiveList.stream()
                    .map(r -> r.getZoneMd5())
                    .collect(Collectors.toList());
            zoneMd5ListVO.setFileMd5(requestVO.getFileMd5());
        }
        zoneMd5ListVO.setZoneMd5List(zoneMd5List);
        return zoneMd5ListVO;
    }

    /**
     * 合并分片
     *
     * @param zoneMd5ListVO
     * @return
     */
    @Override
    public void mergeZoneFile(ZoneMd5ListVO zoneMd5ListVO) throws Exception {
        //根据批次号查询分片信息
        List<FileSplitReceive> fileSplitReceiveList = fileSplitReceiveService.findByFileMd5(zoneMd5ListVO.getFileMd5());
        List<String> saveMd5List = fileSplitReceiveList.stream()
                .map(fileSplitReceive -> fileSplitReceive.getZoneMd5())
                .collect(Collectors.toList());
        log.info("协会存在的分片信息:{}", JSONObject.toJSONString(saveMd5List));

        //判断分片信息是否和会员端的一致，如果不一致不合并
        List<String> md5List = zoneMd5ListVO.getZoneMd5List();
        log.info("需要合并的分片信息:{}", JSONObject.toJSONString(md5List));

        Boolean compareFlag = CompareUtil.compareByString(saveMd5List, md5List);
        if (!compareFlag) {
            throw new RuntimeException("需要合并的分片信息不正确");
        }
        //合并分片信息
        String combineFilePath = fileSplitProperties.getBasePath() + File.separator + zoneMd5ListVO.getFileFullName();
        List<String> zoneFilePathList = fileSplitReceiveList.stream()
                .map(fileSplitReceive -> fileSplitReceive.getZonePath())
                .collect(Collectors.toList());

        String stopWatchTitle = "服务端合并分片:" + zoneMd5ListVO.getFileFullName();
        StopWatch stopWatch = new StopWatch(stopWatchTitle);
        stopWatch.start("合并分片");
        FileCombineUtill.combineFile(zoneFilePathList, combineFilePath);
        stopWatch.stop();
        log.info(stopWatch.prettyPrint());
        log.info("总耗时:{}秒", stopWatch.getTotalTimeSeconds());
    }
}
